﻿using EventMgrLib;
using Newtonsoft.Json;
using Sunny.UI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Reflection;
using System.Security.Policy;
using System.Threading;
using CanVasLib.Diagram;

namespace SmartMotion.Core
{
    public class ActionItem : Entity
    {
        #region Protect

        protected EventMgr Em;

        #endregion Protect

        #region 构造与析构

        public ActionItem()
        {
            Em = EventMgr.Ins;
            StepID = Guid.NewGuid();
            Parms = new List<MethodParms>();
            ParaTypes = new List<string>();
            ParaNames = new List<string>();
            connectors = new List<Connector>();
            ToolRectangle = new Rectangle(0, 0, 120, 70)
            {
                Height = 33
            };
        }

        #endregion 构造与析构

        #region 私有字段

        private string _goToLabel;
        private string _status;
        private Bitmap _bitIcon;
        private string _time;
        private string _dll;
        private string _typeName;
        private string _methodName;
        private List<MethodParms> _parms;
        private List<string> _paraTypes;
        private List<string> _paraNames;
        private string _objName;
        private bool _isStatic;
        private string _returnType;
        private string _returnObjName;
        private string _group;
        private string _icon;
        private string _itemName;
        private int _index;
        private bool _inUse;
        private string _description;
        private object _tag;
        private int _beforeWait;
        private int _afterWait;
        private int _overTime;
        private Guid _stepId;
        private object _obj;
        private bool _enableSuccessGoto;
        private bool _enableFailedGoto;
        private Guid _successStepId;
        private Guid _failStepId;
        private bool _failStopFlow;
        private bool _failStopAllFlow;
        private bool _successStopFlow;
        private bool _successStopAllFlow;

        #endregion 私有字段

        #region 公有属性

        [Browsable(true), Description("工具来自哪个Dll"), Category("程序集"), ReadOnly(true)]
        public string Dll
        {
            get { return _dll; }
            set { _dll = value; }
        }

        [Browsable(true), Description("类名"), Category("程序集"), ReadOnly(true)]
        public string TypeName
        {
            get { return _typeName; }
            set { _typeName = value; }
        }

        [Browsable(true), Description("方法名"), Category("程序集"), ReadOnly(true)]
        public string MethodName
        {
            get { return _methodName; }
            set { _methodName = value; }
        }

        [Browsable(true), Description("参数列表"), Category("程序集"), ReadOnly(true)]
        public List<MethodParms> Parms
        {
            get { return _parms; }
            set { _parms = value; }
        }

        [Browsable(true), Description("参数列表类型"), Category("程序集"), ReadOnly(true)]
        public List<string> ParaTypes
        {
            get { return _paraTypes; }
            set { _paraTypes = value; }
        }

        [Browsable(true), Description("参数列表名称"), Category("程序集"), ReadOnly(true)]
        public List<string> ParaNames
        {
            get { return _paraNames; }
            set { _paraNames = value; }
        }
        [Browsable(true), Description("参数列表的Guid"), Category("程序集"), ReadOnly(true)]
        public List<string> VarIDs { get; set; }

        [Browsable(true), Description("执行方法的对象"), Category("程序集"), ReadOnly(true)]
        [JsonIgnore]
        public object Obj
        {
            get { return _obj; }
            set { _obj = value; }
        }

        [Browsable(true), Description("执行方法的对象名称"), Category("程序集"), ReadOnly(true)]
        public string ObjName
        {
            get { return _objName; }
            set { _objName = value; }
        }

        [Browsable(true), Description("返回值类型是否是静态的"), Category("程序集"), ReadOnly(true)]
        public bool IsStatic
        {
            get { return _isStatic; }
            set { _isStatic = value; }
        }

        [Browsable(true), Description("返回值类型"), Category("程序集"), ReadOnly(true)]
        public string ReturnType
        {
            get { return _returnType; }
            set { _returnType = value; }
        }

        [Browsable(true), Description("返回值对象名称"), Category("程序集"), ReadOnly(true)]
        public string ReturnObjName
        {
            get { return _returnObjName; }
            set { _returnObjName = value; }
        }

        [Browsable(true), Description("工具箱里的分组"), Category("工具箱"), ReadOnly(true)]
        public string Group
        {
            get { return _group; }
            set { _group = value; }
        }

        [Browsable(true), Description("工具图标"), Category("公用"), ReadOnly(true)]
        public string Icon
        {
            get { return _icon; }
            set { _icon = value; }
        }

        [Browsable(true), Description("名称"), Category("公用"), ReadOnly(false)]
        public string ItemName
        {
            get { return text; }
            set
            {
                SetProperty(ref text, value);
            }
        }

        [Browsable(true), Description("序号"), Category("编辑界面"), ReadOnly(true)]
        public int Index
        {
            get { return _index; }
            set
            {
                SetProperty(ref _index, value);
            }
        }

        [Browsable(true), Description("是否启用"), Category("编辑界面")]
        public bool InUse
        {
            get { return _inUse; }
            set { SetProperty(ref _inUse, value); }
        }

        [JsonIgnore]
        public  Bitmap BitIcon
        {
            get
            {
                if (ToolMgr.Ins.Images.ContainsKey(Icon))
                {
                    _bitIcon = ToolMgr.Ins.Images[Icon];
                }
                return _bitIcon;
            }
            set { _bitIcon = value; }
        }

        [Browsable(true), Description("描述"), Category("编辑界面")]
        public string Description
        {
            get { return _description; }
            set { SetProperty(ref _description, value); }
        }

        [Browsable(true), Description("执行状态"), Category("编辑界面"), ReadOnly(true)]
        public string Status
        {
            get { return _status; }
            set
            {
                SetProperty(ref _status, value);
            }
        }

        [Browsable(true), Description("耗时"), Category("编辑界面"), ReadOnly(true)]
        public string Time
        {
            get
            {
                return _time;
            }
            set
            {
                SetProperty(ref _time, value);
            }
        }

        [Browsable(true), Description("备用属性,用于不想创建属性时"), Category("Tag"), ReadOnly(false)]
        public object Tag
        {
            get { return _tag; }
            set { _tag = value; }
        }

        [Browsable(true), Description("执行前等待"), Category("时间")]
        public int BeforeWait
        {
            get { return _beforeWait; }
            set { _beforeWait = value; }
        }

        [Browsable(true), Description("执行后等待"), Category("时间")]
        public int AfterWait
        {
            get { return _afterWait; }
            set { _afterWait = value; }
        }

        [Browsable(true), Description("超时时间"), Category("时间")]
        public int OverTime
        {
            get { return _overTime; }
            set { _overTime = value; }
        }

        [Browsable(true), Description("步骤ID"), Category("跳转"), ReadOnly(true)]
        public Guid StepID
        {
            get { return _stepId; }
            set { _stepId = value; }
        }

        [Browsable(true), Description("跳转标签"), Category("跳转"), ReadOnly(true)]
        public string GoToLabel
        {
            get
            {
                _goToLabel = Index + ItemName;
                return _goToLabel;
            }
            set { _goToLabel = value; }
        }

        [Browsable(true), Description("启用成功跳转"), Category("跳转")]
        public bool EnableSuccessGoto
        {
            get { return _enableSuccessGoto; }
            set { _enableSuccessGoto = value; }
        }

        [Browsable(true), Description("启用失败跳转"), Category("跳转")]
        public bool EnableFailedGoto
        {
            get { return _enableFailedGoto; }
            set { _enableFailedGoto = value; }
        }

        [Browsable(true), Description("成功后跳转位置ID"), Category("跳转"), ReadOnly(true)]
        public Guid SuccessStepID
        {
            get { return _successStepId; }
            set { _successStepId = value; }
        }

        [Browsable(true), Description("失败后跳转位置ID"), Category("跳转"), ReadOnly(true)]
        public Guid FailStepID
        {
            get { return _failStepId; }
            set { _failStepId = value; }
        }

        [Browsable(true), Description("失败后停止此流程"), Category("跳转")]
        public bool FailStopFlow
        {
            get { return _failStopFlow; }
            set { _failStopFlow = value; }
        }

        [Browsable(true), Description("失败后停止所有流程"), Category("跳转")]
        public bool FailStopAllFlow
        {
            get { return _failStopAllFlow; }
            set { _failStopAllFlow = value; }
        }

        [Browsable(true), Description("失败后停止此流程"), Category("跳转")]
        public bool SuccessStopFlow
        {
            get { return _successStopFlow; }
            set { _successStopFlow = value; }
        }

        [Browsable(true), Description("失败后停止所有流程"), Category("跳转")]
        public bool SuccessStopAllFlow
        {
            get { return _successStopAllFlow; }
            set { _successStopAllFlow = value; }
        }
        [Browsable(false)]
        public string ObjGuid { get; set; } = Guid.NewGuid().ToString();
        [Browsable(false)]
        public string ReturnObjGuid { get; set; } = Guid.NewGuid().ToString();
        [JsonIgnore, Browsable(false)]
        public int NextIndex { get; set; }
        [JsonIgnore, Browsable(false)]
        public Flow Flow { get;  set; }
        [JsonIgnore, Browsable(false)]
        public int CurrentIndex { get; set; }


        private bool _waitAny;
        [Browsable(true), Description("只要有一个前置任务执行完就执行此任务，默认是等待所有前置任务执行完"), Category("任务调度")]
        public bool WaitAny
        {
            get { return _waitAny; }
            set { SetProperty(ref _waitAny, value); }
        }

        //private bool _isRunning;
        //[Browsable(true), Description("标记任务是否正在执行中"), Category("任务调度"),ReadOnly(true)]
        //public bool IsRunning
        //{
        //    get { return _isRunning; }
        //    set { SetProperty(ref _isRunning, value); }
        //}
        //private bool _isRuned;
        //[Browsable(true), Description("标记任务是否已执行"), Category("任务调度"),ReadOnly(true)]
        //public bool IsRuned
        //{
        //    get { return _isRuned; }
        //    set { SetProperty(ref _isRuned, value); }
        //}

        #endregion 公有属性 

        #region 公有方法

        public virtual dynamic CopyFromTool()
        {
            dynamic actionItem = Activator.CreateInstance(this.GetType());
            actionItem.Dll = this.Dll;
            actionItem.ItemName = this.ItemName;
            actionItem.TypeName = this.TypeName;
            actionItem.MethodName = this.MethodName;
            actionItem.IsStatic = this.IsStatic;
            actionItem.Icon = this.Icon;
            actionItem.ReturnType = this.ReturnType;
            ParaTypes.ForEach(item => actionItem.ParaTypes.Add(item));
            for (int i = 0; i < ParaTypes.Count; i++)
            {
                string item = ParaTypes[i];
                var methodparm = new MethodParms() { Name = ParaNames[i], Type = item, InputOrSelect = true };
                actionItem.Parms.Add(methodparm);
            }
            return actionItem;
        }

        public virtual bool Initilize()
        {
            InitilizeMethod();
            return true;
        }

        public virtual UIPage GetParmsPage()
        {
            var method = InitilizeMethod();
            if (method == null) return null;

            ParaPage pageAtt = (ParaPage)method.GetCustomAttribute(typeof(ParaPage));
            if (pageAtt != null)
            {
                return pageAtt.GetParaPage(this);
            }

            return new FrmActionItem(this);
        }

        public virtual UIForm GetConfigForm()
        {
            return null;
        }

        public virtual bool Run()
        {
            Status = "开始执行...";
            //运行前做一些事情
            var sw = Stopwatch.StartNew();
            if (BeforeWait > 0) Thread.Sleep(BeforeWait);
            //执行具体的方法
            var result = RunMethod();
            if (this.Flow != null) NextActionItemIndex(result);
           
            Status = result ? "成功" : "失败";
            //运行后做一些事情
            if (AfterWait > 0) Thread.Sleep(AfterWait);

            Time = sw.ElapsedMilliseconds.ToString();
            Em.GetEvent<DebugMessage>().Publish($"{ItemName}运行了一次{MethodName} 耗时{Time}");
            State = ActionState.Completed;
          
            return true;
        }

        protected virtual void NextActionItemIndex(bool result)
        {
            //this.Flow.NextIndex++;
        }

        protected virtual bool RunMethod()
        {
            try
            {
                //var vars = GlobalVars.Ins.Vars[GlobalVars.FlowVars];



                #region 反射出方法
                var method = InitilizeMethod();
                if (method == null) return false;

                #endregion 反射出方法

                #region 执行方法的对象

                Obj = null;

                if (!string.IsNullOrEmpty(ObjName))
                {
                    Obj = GlobalVars.Ins.GetVar(ObjGuid).Value;
                }

                #endregion 执行方法的对象

                #region 参数数组对象

                var objs = new List<object>();
                for (var index = 0; index < Parms.Count; index++)
                {
                    var item = Parms[index];
                    object temp = null;
                    if (!item.InputOrSelect)
                    {
                        //if (vars.ContainsKey(item.VarName)) temp = vars[item.VarName].Value;
                        temp = GlobalVars.Ins.GetVar(item.VarGuid).Value;
                    }
                    else
                    {
                        var valueType = Type.GetType(ParaTypes[index]);
                        if (valueType == typeof(int)) temp = Convert.ToInt32(item.Value);
                        else if (valueType == typeof(uint)) temp = Convert.ToUInt32(item.Value);
                        else if (valueType == typeof(short)) temp = Convert.ToInt16(item.Value);
                        else if (valueType == typeof(ushort)) temp = Convert.ToUInt16(item.Value);
                        else if (valueType == typeof(long)) temp = Convert.ToInt64(item.Value);
                        else if (valueType == typeof(ulong)) temp = Convert.ToUInt64(item.Value);
                        else if (valueType == typeof(Single)) temp = Convert.ToSingle(item.Value);
                        else if (valueType == typeof(double)) temp = Convert.ToDouble(item.Value);
                        else
                        {
                            temp = item.Value;
                        }
                    }
                    if (temp != null) objs.Add(temp);
                }

                #endregion 参数数组对象

                #region 执行

                object[] objArray = null;
                if (objs.Count > 0)
                {
                    objArray = objs.ToArray();
                }
                var result = method.Invoke(Obj, objArray);

                #endregion 执行

                #region 处理返回值

                if (!ReturnType.Contains("Void") && !string.IsNullOrEmpty(ReturnObjName))
                {
                    var varObj = GlobalVars.Ins.GetVar(ReturnObjGuid);
                    varObj.Value = result;
                }

                #endregion 处理返回值
            }
            catch (Exception e)
            {
                Em.GetEvent<DebugMessage>().Publish($"运行{ItemName}时出现异常:{e.Message}");
                return false;
            }

            return true;
        }

        private MethodInfo InitilizeMethod()
        {
            string fileName = Environment.CurrentDirectory + "\\" + Dll;
            var curAssembly = Assembly.LoadFile(fileName);
            var tp = curAssembly.GetType(TypeName);
            var method = tp.GetMethod(MethodName, ParaTypes.Select(Type.GetType).ToArray());//传入参数列表才能获得重载方法

            return method;
        }

        #endregion 公有方法

        //---------------下面是流程图相关内容

        #region Fields

        private int _borderLength = 20;
        private int _marginBottom = 5;

        /// <summary>
        /// 固定底部连接器
        /// </summary>
        protected Connector cBottom, cLeft, cRight, cTop;

        /// <summary>
        /// the rectangle on which any shape lives
        /// </summary>
        public Rectangle ToolRectangle { get; set; }

        /// <summary>
        /// the collection of connectors onto which you can attach a connection
        /// </summary>
        protected List<Connector> connectors;

        /// <summary>
        /// the text on the shape
        /// </summary>
        protected string text = string.Empty;

        //protected Image Icon = null;
        //public int Index = -1;

        [Browsable(false)]
        public double Scale = 1;

        private bool showBorder = true;

        /// <summary>
        /// the backcolor of the shapes
        /// </summary>
        protected Color backGroundColor = Color.White;

        protected Color borderColor = Color.Black;

        protected Color borderSelectedColor = Color.GreenYellow;

        #endregion Fields

        #region Properties

        /// <summary>
        /// Gets or sets the connectors of this shape
        /// </summary>
        [Browsable(false), JsonIgnore]
        public List<Connector> Connectors
        {
            get { return connectors; }
            set { connectors = value; }
        }

        [Browsable(true), Description("显示底部源点"), Category("Layout")]
        public bool EnableBottomSourceConnector { get; set; } = true;

        [Browsable(true), Description("显示左侧源点"), Category("Layout")]
        public bool EnableLeftSourceConnector { get; set; } = false;

        [Browsable(true), Description("显示右侧源点"), Category("Layout")]
        public bool EnableRightSourceConnector { get; set; } = false;

        [Browsable(true), Description("显示顶部源点"), Category("Layout")]
        public bool EnableTopSourceConnector { get; set; } = true;

        [Browsable(true), Description("显示底部目标点"), Category("Layout")]
        public bool EnableBottomTargetConnector { get; set; } = false;

        [Browsable(true), Description("显示左侧目标点"), Category("Layout")]
        public bool EnableLeftTargetConnector { get; set; } = false;

        [Browsable(true), Description("显示右侧目标点"), Category("Layout")]
        public bool EnableRightTargetConnector { get; set; } = false;

        [Browsable(true), Description("显示顶部目标点"), Category("Layout")]
        public bool EnableTopTargetConnector { get; set; } = false;

        [Browsable(false)]
        public virtual string ShapeName => "ShapeBase";

        [Browsable(false)]
        public virtual double ToolBoxScale => 1;

        /// <summary>
		/// Gets or sets the width of the shape
		/// </summary>
		[Browsable(true), Description("宽度"), Category("Layout")]
        public int Width
        {
            get { return (int)(this.ToolRectangle.Width * Scale); }
            set { Resize(value, this.Height); }
        }

        /// <summary>
        /// Gets or sets the height of the shape
        /// </summary>
        [Browsable(true), Description("高度"), Category("Layout")]
        public int Height
        {
            get { return (int)(this.ToolRectangle.Height * Scale); }
            set { Resize(this.Width, value); }
        }

        /// <summary>
        /// Gets or sets the text of the shape
        /// </summary>
        [Browsable(true), Description("显示的文本"), Category("Layout")]
        public string Text
        {
            get { return this.text; }
            set { this.text = value; this.Invalidate(); }
        }

        /// <summary>
        /// the x-coordinate of the upper-left corner
        /// </summary>
        [Browsable(true), Description("X坐标"), Category("Layout")]
        public int X
        {
            get { return ToolRectangle.X; }
            set
            {

                Point p = new Point(value - ToolRectangle.X, 0);

                if (Site != null)
                {
                    this.Move(p);
                    Site.Invalidate(); //note that 'this.Invalidate()' will not be enough
                }

            }
        }

        /// <summary>
        /// the y-coordinate of the upper-left corner
        /// </summary>
        [Browsable(true), Description("Y坐标"), Category("Layout")]
        public int Y
        {
            get { return ToolRectangle.Y; }
            set
            {
                Point p = new Point(0, value - ToolRectangle.Y);
                if (Site != null)
                {
                    this.Move(p);
                    Site.Invalidate();
                }

            }
        }

        [Browsable(true), Description("是否显示边框"), Category("Layout")]
        public bool ShowBorder
        {
            get { return showBorder; }
            set { showBorder = value; Invalidate(); }
        }

        /// <summary>
		/// The backcolor of the shape
		/// </summary>
		[Browsable(true), Description("背景颜色"), Category("Layout")]
        public Color BackGroundColor
        {
            get { return backGroundColor; }
            set { backGroundColor = value; Invalidate(); }
        }

        [Browsable(true), Description("边框颜色"), Category("Layout")]
        public Color BoderColor
        {
            get { return borderColor; }
            set { borderColor = value; Invalidate(); }
        }

        [Browsable(true), Description("边框选中后颜色"), Category("Layout")]
        public Color BoderSelectedColor
        {
            get { return borderSelectedColor; }
            set { borderSelectedColor = value; Invalidate(); }
        }

        /// <summary>
        /// Gets or sets the location of the tool;
        /// </summary>
        [Browsable(false)]
        public Point Location
        {
            get { return new Point(this.ToolRectangle.X, this.ToolRectangle.Y); }
            set
            {
                //we use the move method but it requires the delta value, not an absolute position!
                Point p = new Point(value.X - ToolRectangle.X, value.Y - ToolRectangle.Y);
                //if you'd use this it would indeed move the shape but not the connector s of the shape
                //this.rectangle.X = value.X; this.rectangle.Y = value.Y; Invalidate();
                this.Move(p);
            }
        }

        private int _cornerRadius = 10;
        private ActionState _state;

        [Browsable(true), Description("圆角率"), Category("Layout")]
        public int CornerRadius
        {
            get
            {
                return _cornerRadius;
            }
            set
            {
                _cornerRadius = value;
            }
        }

        #endregion Properties


        #region Methods

        /// <summary>
        /// Summarizes the initialization used by the constructors
        /// </summary>
        public void InitCanvas(Canvas site)
        {
            this.site = site;


        }

        /// <summary>
        /// 被画布调用，连接点被击中
        /// </summary>
        /// <param name="p">the mouse coordinates</param>
        /// <param name="targetNode">是否为目标节点</param>
        /// <returns>the connector hit by the mouse</returns>
        public virtual Connector HitConnector(Point p, bool targetNode = false)
        {
            Point point0 = new Point(0, 0);
            if (this.site != null) point0 = this.site.ViewOriginPoint.GetPoint();
            Rectangle rect = new Rectangle(p, new Size(5, 5));

            #region 上

            var contentionRectangle = new Rectangle(
                (ToolRectangle.Width - _borderLength) / 2 + ToolRectangle.X + point0.X,
                (int)((ToolRectangle.Y + point0.Y - _marginBottom) - _borderLength * Math.Sin(Math.PI / 3)),
                _borderLength, _borderLength);

            if (contentionRectangle.Contains(rect))
            {
                if (!EnableTopSourceConnector)
                {
                    return null;
                }

                Point point = cTop.Point.GetPoint();
                point.Offset(point0.X - 7, point0.Y - 7);
                //return base.HitConnector(point);
                return cTop;
            }

            #endregion 上

            #region 下

            contentionRectangle = new Rectangle(
                (ToolRectangle.Width - _borderLength) / 2 + ToolRectangle.X + point0.X,
                ToolRectangle.Y + point0.Y + ToolRectangle.Height + _marginBottom,
                _borderLength, _borderLength);

            if (contentionRectangle.Contains(rect))
            {
                if (!EnableBottomSourceConnector)
                {
                    return null;
                }

                Point point = cBottom.Point.GetPoint();
                point.Offset(point0.X - 7, point0.Y - 7);
                //return base.HitConnector(point);
                return cBottom;
            }

            #endregion 下

            #region 右

            contentionRectangle = new Rectangle(
                ToolRectangle.Width + ToolRectangle.X + point0.X + _marginBottom,
                (ToolRectangle.Height - _borderLength) / 2 + ToolRectangle.Y + point0.Y,
                _borderLength, _borderLength);

            if (contentionRectangle.Contains(rect))
            {
                if (!EnableRightSourceConnector)
                {
                    return null;
                }

                Point point = cRight.Point.GetPoint();
                point.Offset(point0.X - 7, point0.Y - 7);
                //return base.HitConnector(point);
                return cRight;
            }

            #endregion 右

            #region 左

            contentionRectangle = new Rectangle(
                ToolRectangle.X + point0.X - _marginBottom - _borderLength,
                (ToolRectangle.Height - _borderLength) / 2 + ToolRectangle.Y + point0.Y,
                _borderLength, _borderLength);

            if (contentionRectangle.Contains(rect))
            {
                if (!EnableLeftSourceConnector)
                {
                    return null;
                }

                Point point = cLeft.Point.GetPoint();
                point.Offset(point0.X - 7, point0.Y - 7);
                //return base.HitConnector(point);
                return cLeft;
            }

            #endregion 左

            for (int k = 0; k < connectors.Count; k++)
            {
                if (connectors[k].Hit(p))
                {
                    if (!targetNode)
                    {
                        if (!EnableBottomSourceConnector && connectors[k].ConnectorDirection == ConnectorDirection.Down)
                        {
                            return null;
                        }

                        if (!EnableTopSourceConnector && connectors[k].ConnectorDirection == ConnectorDirection.Up)
                        {
                            return null;
                        }

                        if (!EnableRightSourceConnector && connectors[k].ConnectorDirection == ConnectorDirection.Right)
                        {
                            return null;
                        }

                        if (!EnableLeftSourceConnector && connectors[k].ConnectorDirection == ConnectorDirection.Left)
                        {
                            return null;
                        }
                    }
                    else
                    {
                        if (!EnableBottomTargetConnector && connectors[k].ConnectorDirection == ConnectorDirection.Down)
                        {
                            return null;
                        }

                        if (!EnableTopTargetConnector && connectors[k].ConnectorDirection == ConnectorDirection.Up)
                        {
                            return null;
                        }

                        if (!EnableRightTargetConnector && connectors[k].ConnectorDirection == ConnectorDirection.Right)
                        {
                            return null;
                        }

                        if (!EnableLeftTargetConnector && connectors[k].ConnectorDirection == ConnectorDirection.Left)
                        {
                            return null;
                        }
                    }

                    connectors[k].Hovered = true;
                    connectors[k].Invalidate();
                    return connectors[k];
                }
                else
                {
                    connectors[k].Hovered = false;
                    connectors[k].Invalidate();
                }
            }
            return null;
        }

        /// <summary>
        /// Resizes the shape and moves the connectors
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public virtual void Resize(int width, int height)
        {
            //this.Rectangle1.Height = height;
            //this.Rectangle1.Width = width;

            if (cBottom != null)
                cBottom.Point = new Point(ToolRectangle.Left + ToolRectangle.Width / 2, ToolRectangle.Bottom);
            if (cLeft != null)
                cLeft.Point = new Point(ToolRectangle.Left, ToolRectangle.Top + ToolRectangle.Height / 2);
            if (cRight != null)
                cRight.Point = new Point(ToolRectangle.Right, ToolRectangle.Top + ToolRectangle.Height / 2);
            if (cTop != null)
                cTop.Point = new Point(ToolRectangle.Left + ToolRectangle.Width / 2, ToolRectangle.Top);
            Invalidate();
        }

        protected override void SiteChanged()
        {
            connectors.Remove(cBottom);
            cBottom = new Connector(new Point(ToolRectangle.Left + ToolRectangle.Width / 2, ToolRectangle.Bottom))
            {
                OwnerEntity = this,
                ConnectorsIndexOfContainEntity = connectors.Count,
                Site = this.site,
                OwnerID = this.ObjectId,
                Index = connectors.Count,
                Name = "Bottom connector",
                ConnectorDirection = ConnectorDirection.Down
            };
            connectors.Add(cBottom);

            connectors.Remove(cLeft);
            cLeft = new Connector(new Point(ToolRectangle.Left, ToolRectangle.Top + ToolRectangle.Height / 2))
            {
                OwnerEntity = this,
                ConnectorsIndexOfContainEntity = connectors.Count,
                Site = this.site,
                OwnerID = this.ObjectId,
                Index = connectors.Count,
                Name = "Left connector",
                ConnectorDirection = ConnectorDirection.Left
            };
            connectors.Add(cLeft);

            connectors.Remove(cRight);
            cRight = new Connector(new Point(ToolRectangle.Right, ToolRectangle.Top + ToolRectangle.Height / 2))
            {
                OwnerEntity = this,
                ConnectorsIndexOfContainEntity = connectors.Count,
                Site = this.site,
                OwnerID = this.ObjectId,
                Index = connectors.Count,
                Name = "Right connector",
                ConnectorDirection = ConnectorDirection.Right
            };
            connectors.Add(cRight);

            connectors.Remove(cTop);
            cTop = new Connector(new Point(ToolRectangle.Left + ToolRectangle.Width / 2, ToolRectangle.Top))
            {
                OwnerEntity = this,
                ConnectorsIndexOfContainEntity = connectors.Count,
                Site = this.site,
                OwnerID = this.ObjectId,
                Index = connectors.Count,
                Name = "Top connector",
                ConnectorDirection = ConnectorDirection.Up
            };
            connectors.Add(cTop);
        }

        /// <summary>
        /// 覆盖抽象绘制方法
        /// </summary>
        /// <param name="g"></param>
        public override void Paint(Graphics g)
        {
            g.SmoothingMode = SmoothingMode.AntiAlias;
            Point point = new Point(0, 0);
            if (this.site != null)
                point = this.site.ViewOriginPoint.GetPoint();

            Brush brush = new SolidBrush(BackGroundColor);
            Rectangle rect = new Rectangle(ToolRectangle.X + point.X, ToolRectangle.Y + point.Y, this.Width, this.Height);
            using (GraphicsPath graphicsPath = CreatePath(rect, (int)(_cornerRadius * Scale)))
            {
                g.FillPath(brush, graphicsPath);
                if (Hovered || isSelected)
                {
                    Pen p = new Pen(BoderSelectedColor, 2F);
                    p.StartCap = LineCap.Round;
                    p.EndCap = LineCap.Round;
                    p.LineJoin = LineJoin.Round;
                    g.DrawPath(p, graphicsPath);
                }
                else if (ShowBorder)
                {
                    Pen p = new Pen(BoderColor);
                    p.StartCap = LineCap.Round;
                    p.EndCap = LineCap.Round;
                    p.LineJoin = LineJoin.Round;
                    g.DrawPath(p, graphicsPath);
                }
            }
            if (this.site != null)
                point = this.site.ViewOriginPoint.GetPoint();

            if (isSelected)
            {
                Point point1, point2, point3;
                Point[] pntArr;

                if (EnableTopSourceConnector)
                {
                    #region 上连接点

                    point1 = new Point(
                        (ToolRectangle.Width - _borderLength) / 2 + ToolRectangle.X + point.X,
                        ToolRectangle.Y + point.Y - _marginBottom);

                    point2 = new Point(
                        (ToolRectangle.Width + _borderLength) / 2 + ToolRectangle.X + point.X,
                        ToolRectangle.Y + point.Y - _marginBottom);

                    point3 = new Point(
                        ToolRectangle.Width / 2 + ToolRectangle.X + point.X,
                        (int)((ToolRectangle.Y + point.Y - _marginBottom) - _borderLength * Math.Sin(Math.PI / 3)));

                    pntArr = new[] { point1, point2, point3 };
                    g.FillPolygon(Brushes.Gold, pntArr);

                    #endregion 上连接点
                }

                if (EnableBottomSourceConnector)
                {
                    #region 下连接点

                    point1 = new Point(
                        (ToolRectangle.Width - _borderLength) / 2 + ToolRectangle.X + point.X,
                        ToolRectangle.Y + point.Y + ToolRectangle.Height + _marginBottom);

                    point2 = new Point(
                        (ToolRectangle.Width + _borderLength) / 2 + ToolRectangle.X + point.X,
                        ToolRectangle.Y + point.Y + ToolRectangle.Height + _marginBottom);

                    point3 = new Point(
                        ToolRectangle.Width / 2 + ToolRectangle.X + point.X,
                        (int)((ToolRectangle.Y + point.Y + ToolRectangle.Height + _marginBottom) + _borderLength * Math.Sin(Math.PI / 3)));

                    pntArr = new[] { point1, point2, point3 };
                    g.FillPolygon(Brushes.Gold, pntArr);

                    #endregion 下连接点
                }

                if (EnableRightSourceConnector)
                {
                    #region 右连接点

                    point1 = new Point(
                        ToolRectangle.Width + ToolRectangle.X + point.X + _marginBottom,
                        (ToolRectangle.Height - _borderLength) / 2 + ToolRectangle.Y + point.Y);

                    point2 = new Point(
                        ToolRectangle.Width + ToolRectangle.X + point.X + _marginBottom,
                        (ToolRectangle.Height + _borderLength) / 2 + ToolRectangle.Y + point.Y);

                    point3 = new Point(
                        (int)(ToolRectangle.Width + ToolRectangle.X + point.X + _marginBottom + _borderLength * Math.Sin(Math.PI / 3)),
                        ToolRectangle.Height / 2 + ToolRectangle.Y + point.Y);

                    pntArr = new[] { point1, point2, point3 };
                    g.FillPolygon(Brushes.Gold, pntArr);

                    #endregion 右连接点
                }

                if (EnableLeftSourceConnector)
                {
                    #region 左连接点

                    point1 = new Point(
                        ToolRectangle.X + point.X - _marginBottom,
                        (ToolRectangle.Height - _borderLength) / 2 + ToolRectangle.Y + point.Y);

                    point2 = new Point(
                        ToolRectangle.X + point.X - _marginBottom,
                        (ToolRectangle.Height + _borderLength) / 2 + ToolRectangle.Y + point.Y);

                    point3 = new Point(
                        (int)(ToolRectangle.X + point.X - _marginBottom - _borderLength * Math.Sin(Math.PI / 3)),
                        ToolRectangle.Height / 2 + ToolRectangle.Y + point.Y);

                    pntArr = new[] { point1, point2, point3 };
                    g.FillPolygon(Brushes.Gold, pntArr);

                    #endregion 左连接点
                }
            }

            for (int k = 0; k < connectors.Count; k++)
            {
                connectors[k].Paint(g);
            }
            //绘制图标
            if (text != string.Empty)
            {
                StringFormat stringFormat = new StringFormat();
                stringFormat.LineAlignment = StringAlignment.Center;
                stringFormat.Alignment = StringAlignment.Center;
                Rectangle rectangle = new Rectangle(this.ToolRectangle.X + point.X, this.ToolRectangle.Y + point.Y, this.ToolRectangle.Width, this.ToolRectangle.Height);
                if (BitIcon != null)
                {
                    g.DrawImage(BitIcon, this.ToolRectangle.X + point.X + 5, this.ToolRectangle.Y + point.Y, 32, 32);
                    Rectangle rectangle1 = new Rectangle(this.ToolRectangle.X + point.X + 10, this.ToolRectangle.Y + point.Y, this.ToolRectangle.Width, this.ToolRectangle.Height);
                    g.DrawString(text, Font, Brushes.Black, rectangle1, stringFormat);
                }
                else
                {
                    g.DrawString(text, Font, Brushes.Black, rectangle, stringFormat);
                }
            }
        }

        /// <summary>
        /// Override the abstract Hit method
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public override bool Hit(System.Drawing.Point p)
        {
            if (this.site == null) return false;
            Point point = new Point(0, 0);
            if (this.site != null)
                point = this.site.ViewOriginPoint.GetPoint();

            p.X = p.X - point.X;
            p.Y = p.Y - point.Y;

            Rectangle r = new Rectangle(p, new Size(5, 5));
            return ToolRectangle.Contains(r);
        }

        /// <summary>
        /// 覆盖抽象的 Invalidate 方法
        /// </summary>
        public override void Invalidate()
        {
            if (this.site == null) return;
            Point point = this.site.ViewOriginPoint.GetPoint();
            Rectangle r = ToolRectangle;
            r.X += point.X;
            r.Y += point.Y;
            r.Offset(-5, -5);
            r.Inflate(20, 20);
            site.Invalidate(r);
        }

        /// <summary>
        ///使用给定的移位移动工具
        /// </summary>
        /// <param name="p">r点位</param>
        public override void Move(Point p)
        {
            if (this.site == null) return;
            ToolRectangle = new Rectangle(ToolRectangle.X + p.X, ToolRectangle.Y + p.Y, ToolRectangle.Width, ToolRectangle.Height);
            //this.ToolRectangle.X += p.X;
            //this.ToolRectangle.Y += p.Y;
            for (int k = 0; k < this.connectors.Count; k++)
            {
                connectors[k].Move(p);
            }
            this.Invalidate();
        }
        /// <summary>
        /// 创建路径
        /// </summary>
        /// <param name="rect"></param>
        /// <param name="cornerRadius"></param>
        /// <returns></returns>
        protected virtual GraphicsPath CreatePath(Rectangle rect, int cornerRadius)
        {
            GraphicsPath roundedRect = new GraphicsPath();
            roundedRect.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);
            roundedRect.AddLine(rect.X + cornerRadius, rect.Y, rect.Right - cornerRadius * 2, rect.Y);
            roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);
            roundedRect.AddLine(rect.Right, rect.Y + cornerRadius * 2, rect.Right, rect.Y + rect.Height - cornerRadius * 2);
            roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y + rect.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
            roundedRect.AddLine(rect.Right - cornerRadius * 2, rect.Bottom, rect.X + cornerRadius * 2, rect.Bottom);
            roundedRect.AddArc(rect.X, rect.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
            roundedRect.AddLine(rect.X, rect.Bottom - cornerRadius * 2, rect.X, rect.Y + cornerRadius * 2);
            roundedRect.CloseFigure();
            return roundedRect;
        }

        #endregion Methods

        #region 状态机
        public enum ActionState
        {
            Idle,
            Ready,
            Running,
            Completed
        }

        public ActionState State
        {
            get => _state;
            set
            {
                _state = value;
                switch (_state)
                {
                    case ActionState.Idle:
                        BackGroundColor = Color.White;
                        break;
                    case ActionState.Ready:
                        break;
                    case ActionState.Running:
                        BackGroundColor = Color.Yellow;
                        break;
                    case ActionState.Completed:
                        BackGroundColor = Color.Aquamarine;
                        break;
                    default:
                        BackGroundColor = Color.White;
                        break;
                }
            }
        }

        #endregion
    }
}   